import { useSettingStore } from '@/store/bpmnProcess/settingStore'
import { getBusinessObject, is } from 'bpmn-js/lib/util/ModelUtil'
import { useModelerStore } from '@/store/bpmnProcess/modelerStore'
import { createModdleElement, getExtensionElementsList } from './bpmnPropertyUtils/extensionElements'
import { without, isDefined } from 'min-dash'

export function getFormTypeValue(element): string | undefined {
  const prefix = useSettingStore().editor.processEngine
  const businessObject = getBusinessObject(element)
  if (isDefined(businessObject.get(`${prefix}:formKey`))) {
    return 'formKey'
  } else if (isDefined(businessObject.get(`${prefix}:formRef`))) {
    return 'formRef'
  } else if (getFormData(element)) {
    return 'formData'
  }
  return ''
}

export function setFormTypeValue(element, value: string | undefined) {
  const prefix = useSettingStore().editor.processEngine
  const modeling = useModelerStore().getModeling
  removePropertiesCommands(element)
  const businessObject = getBusinessObject(element)
  let extensionElements = businessObject.get('extensionElements')

  if (value === 'formData') {
    if (!extensionElements) {
      extensionElements = createModdleElement('bpmn:ExtensionElements', { values: [] }, businessObject)
      modeling.updateModdleProperties(element, businessObject, { extensionElements })
    }
    const parent = extensionElements
    const formData = createModdleElement(`${prefix}:FormData`, { fields: [] }, parent)
    modeling.updateModdleProperties(element, extensionElements, { values: [...extensionElements.get('values'), formData] })
  } else if (value === 'formKey') {
    modeling.updateModdleProperties(element, businessObject, { [`${prefix}:formKey`]: '' })
  } else if (value === 'formRef') {
    modeling.updateModdleProperties(element, businessObject, { [`${prefix}:formRef`]: '' })
  }
}

// 1 camunda表单
// 表单引用
export function getFormRefValue(element) {
  const prefix = useSettingStore().editor.processEngine
  const businessObject = getBusinessObject(element)
  return businessObject.get(`${prefix}:formRef`)
}
export function setFormRefValue(element, value) {
  const prefix = useSettingStore().editor.processEngine
  const modeling = useModelerStore().getModeling
  modeling.updateProperties(element, {
    [`${prefix}:formRef`]: value
  })
}

// 表单绑定
export function getFormRefBindingValue(element) {
  const prefix = useSettingStore().editor.processEngine
  const businessObject = getBusinessObject(element)
  return businessObject.get(`${prefix}:formRefBinding`) || 'latest'
}
export function setFormRefBindingValue(element, value) {
  const prefix = useSettingStore().editor.processEngine
  const modeling = useModelerStore().getModeling
  modeling.updateProperties(element, {
    [`${prefix}:formRefBinding`]: value
  })
}

// 表单绑定版本
export function getFormRefVersionValue(element) {
  const prefix = useSettingStore().editor.processEngine
  const businessObject = getBusinessObject(element)
  return businessObject.get(`${prefix}:formRefVersion`)
}
export function setFormRefVersionValue(element, value) {
  const prefix = useSettingStore().editor.processEngine
  const modeling = useModelerStore().getModeling
  modeling.updateProperties(element, {
    [`${prefix}:formRefVersion`]: value
  })
}

// 2 嵌入式或外部任务表单
// 表单键
export function getFormKeyValue(element) {
  const prefix = useSettingStore().editor.processEngine
  const businessObject = getBusinessObject(element)
  return businessObject.get(`${prefix}:formKey`)
}
export function setFormKeyValue(element, value) {
  const prefix = useSettingStore().editor.processEngine
  const modeling = useModelerStore().getModeling
  modeling.updateProperties(element, {
    [`${prefix}:formKey`]: value
  })
}

// 3 生成的任务表单
// 业务标识
export function getFormBusinessKeyValue(element) {
  const prefix = useSettingStore().editor.processEngine
  // const businessObject = getBusinessObject(element)
  const formData = getFormData(element)
  return formData.get(`${prefix}:businessKey`) || ''
}
export function setFormBusinessKeyValue(element, value) {
  const prefix = useSettingStore().editor.processEngine
  const modeling = useModelerStore().getModeling
  // const businessObject = getBusinessObject(element)
  const formData = getFormData(element)
  modeling.updateModdleProperties(element, formData, {
    [`${prefix}:businessKey`]: value
  })
}
export function isFormBusinessKey(element) {
  return is(element, 'bpmn:StartEvent') && hasFormFields(element)
}
function hasFormFields(element) {
  const prefix = useSettingStore().editor.processEngine
  const businessObject = getBusinessObject(element)
  const formData = getFormData(businessObject)
  return formData && formData.get(`${prefix}:fields`).length
}
export function getBusinessKeyOptions(element) {
  const formData = getFormData(element)
  const options = []
  const fields = formData.get('fields')
  fields.forEach((field) => {
    options.push({
      value: field.id,
      label: field.label
    })
  })
  return options
}

export function getFormFieldsTypeList() {
  return [
    { label: '布尔', value: 'boolean' },
    { label: '日期', value: 'date' },
    { label: '枚举', value: 'enum' },
    { label: '长整型', value: 'long' },
    { label: '字符串', value: 'string' },
    { label: '自定义', value: 'custom' }
  ]
}
export function getFormFieldsTypeObject() {
  return {
    boolean: '布尔',
    date: '日期',
    enum: '枚举',
    long: '长整型',
    string: '字符串'
  }
}

// 3 生成的任务表单
// 表单字段数据
// const CUSTOM_TYPE_VALUE = '',
// DEFINED_TYPE_VALUES = ['boolean', 'date', 'enum', 'long', 'string', undefined]
export function getFormDataValue(element) {
  return getFormFieldsList(element) || []
}
export function addFormField(element, options) {
  const { id, label, type } = options
  const prefix = useSettingStore().editor.processEngine
  const modeling = useModelerStore().getModeling
  // const businessObject = getBusinessObject(element)
  const formData = getFormData(element)
  const formField = createModdleElement(`${prefix}:FormField`, { id, label, type }, formData)
  if (options.defaultValue) {
    formField.defaultValue = options.defaultValue
  }
  if (options.value && options.value.length > 0) {
    addEnumValue(element, formField, options.value)
  }
  if (options.constraint && options.constraint.length > 0) {
    addConstraint(element, formField, options.constraint)
  }
  if (options.property && options.property.length > 0) {
    addProperty(element, formField, options.property)
  }
  modeling.updateModdleProperties(element, formData, {
    fields: [...formData.get('fields'), formField]
  })
}

function addEnumValue(element, formField, options) {
  const prefix = useSettingStore().editor.processEngine
  const modeling = useModelerStore().getModeling
  const values = options.map((item) => {
    return createModdleElement(`${prefix}:Value`, item, formField)
  })
  modeling.updateModdleProperties(element, formField, {
    values: [...formField.get('values'), ...values]
  })
}

function addConstraint(element, formField, options) {
  const prefix = useSettingStore().editor.processEngine
  const modeling = useModelerStore().getModeling
  const businessObject = getBusinessObject(element)
  let validation = formField.get('validation')
  if (!validation) {
    validation = createModdleElement(`${prefix}:Validation`, {}, businessObject)
    modeling.updateModdleProperties(element, formField, {
      validation
    })
  }
  const constraints = options.map((item) => {
    return createModdleElement(`${prefix}:Constraint`, item, validation)
  })
  modeling.updateModdleProperties(element, validation, {
    constraints: [...validation.get('constraints'), ...constraints]
  })
}

function addProperty(element, formField, options) {
  const prefix = useSettingStore().editor.processEngine
  const modeling = useModelerStore().getModeling
  const businessObject = getBusinessObject(element)
  let properties = formField.get('properties')
  if (!properties) {
    properties = createModdleElement(`${prefix}:Properties`, {}, businessObject)
    modeling.updateModdleProperties(element, formField, {
      properties
    })
  }
  const propertyList = options.map((item) => {
    return createModdleElement(`${prefix}:Property`, item, properties)
  })
  modeling.updateModdleProperties(element, properties, {
    values: [...properties.get('values'), ...propertyList]
  })
}

export function editFormField(element, options, index) {
  const { id, label, type } = options
  const modeling = useModelerStore().getModeling
  const formFields = getFormFieldsList(element)
  const currentField = formFields[index]
  currentField.id = id
  currentField.label = label
  currentField.type = type
  if (options.defaultValue) {
    currentField.defaultValue = options.defaultValue
  }
  if (currentField.values) {
    delete currentField.values
  }
  if (currentField.validation) {
    delete currentField.validation
  }
  if (currentField.properties) {
    delete currentField.properties
  }
  if (options.value && options.value.length > 0) {
    addEnumValue(element, currentField, options.value)
  }
  if (options.constraint && options.constraint.length > 0) {
    addConstraint(element, currentField, options.constraint)
  }
  if (options.property && options.property.length > 0) {
    addProperty(element, currentField, options.property)
  }
  modeling.updateModdleProperties(element, formFields[index], currentField)
}

export function removeFormField(element, formField) {
  const modeling = useModelerStore().getModeling
  const formData = getFormData(element)
  const formFields = getFormFieldsList(element)
  if (!formFields || !formFields.length) {
    return
  }
  const fields = without(formData.get('fields'), formField)
  modeling.updateModdleProperties(element, formData, { fields })
}

const FORM_KEY_PROPS = {
  'camunda:formRef': undefined,
  'camunda:formRefBinding': undefined,
  'camunda:formRefVersion': undefined
}

const FORM_REF_PROPS = {
  'camunda:formKey': undefined
}

function removePropertiesCommands(element) {
  const modeling = useModelerStore().getModeling
  const businessObject = getBusinessObject(element)
  const extensionElements = businessObject.get('extensionElements')
  // (1) reset formKey and formRef
  modeling.updateModdleProperties(element, businessObject, { ...FORM_KEY_PROPS, ...FORM_REF_PROPS })

  // (2) remove formData if defined
  if (extensionElements && getFormData(element)) {
    modeling.updateModdleProperties(element, extensionElements, { values: without(extensionElements.get('values'), getFormData(element)) })
  }
}

export function isFormSupported(element) {
  return (is(element, 'bpmn:StartEvent') && !is(element.parent, 'bpmn:SubProcess')) || is(element, 'bpmn:UserTask')
}

export function isFormDataSupported(element) {
  const formData = getFormData(element)
  return ((is(element, 'bpmn:StartEvent') && !is(element.parent, 'bpmn:SubProcess')) || is(element, 'bpmn:UserTask')) && formData
}

function getFormData(element) {
  const prefix = useSettingStore().editor.processEngine
  const bo = getBusinessObject(element)
  return getExtensionElementsList(bo, `${prefix}:FormData`)[0]
}
function getFormFieldsList(element) {
  const businessObject = getBusinessObject(element)
  const formData = getFormData(businessObject)
  return formData && formData.fields
}

export function getFormTypeList() {
  return [
    { label: 'Camunda表单', value: 'formRef' },
    { label: '嵌入式或外部任务表单', value: 'formKey' },
    { label: '生成任务表单', value: 'formData' }
  ]
}

export function getBindingList() {
  return [
    { value: 'deployment', label: '部署版本' },
    { value: 'latest', label: '最新版本' },
    { value: 'version', label: '指定版本' }
  ]
}
